package tables

import (
	"database/sql/driver"
	"fmt"
	jsoniter "github.com/json-iterator/go"
	"gorm.io/gorm"
	"time"
)

var FormatTime = "2006-01-02 15:04:05"

type BaseModel struct {
	ID        int32          `gorm:"primary_key;type:int"`
	CreatedAt *MyTime        `gorm:"column:create_time"`
	UpdatedAt *MyTime        `gorm:"column:update_time"`
	DeleteAt  gorm.DeletedAt `gorm:"index"`
}

type MyTime struct {
	time.Time
}

func (t *MyTime) Value() (driver.Value, error) {
	var zeroTime time.Time
	tempT := time.Now().UTC().Format(FormatTime)
	fprTime, _ := time.ParseInLocation(FormatTime, tempT, time.Local)

	if fprTime.UnixNano() == zeroTime.UnixNano() {
		return nil, nil
	}
	return fprTime, nil
}

func (t *MyTime) Scan(v interface{}) error {
	value, ok := v.(time.Time)
	if ok {
		*t = MyTime{Time: value}
		return nil
	}
	return fmt.Errorf("can not convert %v to timestamp", v)
}

// 钩子函数
func (g *BaseModel) BeforeCreate(tx *gorm.DB) error {
	t := time.Now().UTC().Format(FormatTime)
	fptTime, err := time.ParseInLocation(FormatTime, t, time.Local)
	if err != nil {
		return err
	}
	g.CreatedAt = &MyTime{Time: fptTime}
	g.UpdatedAt = &MyTime{Time: fptTime}
	return nil
}

// 钩子函数
func (b *BaseModel) BeforeUpdate(scope *gorm.DB) error {
	t := time.Now().UTC().Format(FormatTime)
	fprTime, err := time.ParseInLocation(FormatTime, t, time.Local)
	if err != nil {
		return err
	}
	b.UpdatedAt = &MyTime{Time: fprTime}
	return nil
}

type GormList []string

func (g *GormList) Scan(value interface{}) error {
	return jsoniter.Unmarshal(value.([]byte), &g)
}

func (g GormList) Value() (driver.Value, error) {
	return jsoniter.Marshal(g)
}

type JSON string

func (g *JSON) Scan(value interface{}) error {
	return jsoniter.Unmarshal(value.([]byte), &g)
}

func (g JSON) Value() (driver.Value, error) {
	return jsoniter.Marshal(g)
}

func Paginate(page, pageSize int) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		if page == 0 {
			page = 1
		}

		switch {
		case pageSize > 100:
			pageSize = 100
		case pageSize <= 100:
			pageSize = 100
		}

		offset := (page - 1) * pageSize
		return db.Offset(offset).Limit(pageSize)
	}
}

func OrderBy(field string) func(db *gorm.DB) *gorm.DB {
	return func(db *gorm.DB) *gorm.DB {
		return db.Order(field)
	}
}
